package com.rtx.edi.platform.jobextend.service.impl;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rtx.api.enums.FieldValidateType;
import com.rtx.api.utils.FieldValidateUtils;
import com.rtx.edi.model.apibaseinfo.po.PlApibaseinfo;
import com.rtx.edi.platform.baseinfo.mapper.PlApibaseinfoMapper;
import com.rtx.edi.platform.jobextend.bean.dto.PlJobDTO;
import com.rtx.edi.platform.jobextend.bean.po.PlJob;
import com.rtx.edi.platform.jobextend.bean.po.PlJobMapping;
import com.rtx.edi.platform.jobextend.job.ApiJob;
import com.rtx.edi.platform.jobextend.mapper.PlJobDetailMapper;
import com.rtx.edi.platform.jobextend.mapper.PlJobMapper;
import com.rtx.edi.platform.jobextend.mapper.PlJobMappingMapper;
import com.rtx.edi.platform.jobextend.service.PlJobService;


@Service
public class PlJobServiceImpl extends ServiceImpl<PlJobMapper, PlJob> implements PlJobService{

	@Autowired
	private SchedulerFactoryBean schedulerFactoryBean;
	
	@Autowired
	PlJobDetailMapper plJobDetailMapper;
	
	@Autowired
	PlJobMappingMapper plJobMappingMapper;
	
	@Autowired
	PlApibaseinfoMapper plApibaseinfoMapper;
	
	
	@Override
	public void selectPlJobList(Page<PlJob> pageParam, PlJob pljob) {
		QueryWrapper<PlJob> where = new QueryWrapper<PlJob>();
		if(StringUtils.hasLength(pljob.getJobName())) {
			where.eq("Job_name", pljob.getJobName());
		}
		if(StringUtils.hasLength(pljob.getJobType())) {
			where.eq("Job_type", pljob.getJobType());
		}
		if(StringUtils.hasLength(pljob.getJobGroup())) {
			where.eq("job_group", pljob.getJobGroup());
		}
		if(StringUtils.hasLength(pljob.getEnable())) {
			where.eq("enable", pljob.getEnable());
		}
		
		baseMapper.selectPage(pageParam, where);
	}

	@Override
	public void add(PlJobDTO jobDto) throws Exception {
		//验证非空字段
		FieldValidateUtils.fieldNotNull(jobDto, FieldValidateType.INSERT);

		PlJob pljob = new PlJob();
		BeanUtils.copyProperties(jobDto, pljob);
		
		QueryWrapper<PlJob> qw = new QueryWrapper<PlJob>();
		qw.eq("job_name", qw);
		boolean existsJob =  baseMapper.exists(qw);
		if(existsJob) {
			throw new RuntimeException("调度任务名称"+jobDto.getJobName()+"已存在!");
		}
		
		baseMapper.insert(pljob);
	}

	@Override
	public void activeJOb(PlJobDTO jobDto) throws Exception {
		PlJob jobPO = baseMapper.selectById(jobDto.getId());
		
		Assert.notNull(jobPO,"调度任务不存在!");
		
		//校验定时任务是否满足激活条件
		activeJobCheck(jobPO);

		//激活qrtz定时任务
		activeQrtzJob(jobPO);
		
		//更新调度任务状态
		updJobStatus(jobPO,"是");
	}
	
	private void updJobStatus(PlJob pljob,String activeStatus) {
		UpdateWrapper<PlJob> where = new UpdateWrapper<PlJob>();
		where.eq("id", pljob.getId());
		pljob.setEnable(activeStatus);
		baseMapper.update(pljob, where);
	}
	
	//校验调度任务是否满足激活条件
	private void activeJobCheck(PlJob jobPO) {
		String type = jobPO.getJobType();
		//校验类型为1 请求API的调度任务是否满足激活条件
		if("1".equals(type)) {
			checkAPIJob(jobPO);
		}
		
		if("2".equals(type)) {
			checkInsertJob(jobPO);
		}
	}
	
	//校验类型为1 请求API的调度任务是否满足激活条件
	private void checkAPIJob(PlJob jobPO) {
		Assert.hasLength(jobPO.getQuerySql(), "查询数据sql（query_sql）字段为空-调度任务无法激活");
		Assert.hasLength(jobPO.getUpdColumn(), "更新状态字段（upd_column）字段为空-调度任务无法激活");
		Assert.hasLength(jobPO.getUpdateSql(), "更新状态sql（update_sql）字段为空-调度任务无法激活");
		Assert.hasLength(jobPO.getStatusField(), "响应是否执行成功字段（status_field）字段为空-调度任务无法激活");
		Assert.hasLength(jobPO.getStatusField(), "执行成功值（successStatusValue）字段为空-调度任务无法激活");
		Assert.notNull(jobPO.getTargetApiId(),"调用目标apiId(target_api_id)字段为空-调度任务无法激活");
		
		QueryWrapper<PlJob> qwm2 = new QueryWrapper<PlJob>();
		qwm2.eq("job_name", jobPO.getJobName());
		boolean exists = baseMapper.exists(qwm2);
		Assert.isTrue(exists, "任务名称（job_name）-"+jobPO.getJobName()+"-已存在");
		
		PlApibaseinfo api =	plApibaseinfoMapper.selectById(jobPO.getTargetApiId());
		Assert.notNull(api,"调用目标api-"+jobPO.getTargetApiId()+"-不存在-调度任务无法激活");

		QueryWrapper<PlJobMapping> qwm = new QueryWrapper<PlJobMapping>();
		qwm.eq("job_id", qwm);
		boolean  mapingExists =  plJobMappingMapper.exists(qwm);
		Assert.isTrue(mapingExists, "api调度任务未配置字段映射-调度任务无法激活");
		
	}
	
	
	//校验类型为2 插入数据库的调度任务是否满足激活条件
	private void checkInsertJob(PlJob jobPO) {
		
	}
	
	//激活qrtz定时任务
	private void activeQrtzJob(PlJob jobPO) throws Exception {
		String jobName = jobPO.getJobName();
		String description = jobPO.getDescription();
		String cron = jobPO.getJobCron();
		String trigger = jobPO.getJobName()+"Trigger";
		String group = jobPO.getJobGroup();
		boolean exists = schedulerFactoryBean.getScheduler().checkExists(new JobKey(jobName, group));
		JobDetail jobDetail = JobBuilder
				.newJob((Class<? extends Job>) ApiJob.class)
				.withIdentity(jobName, group)
				.withDescription(description)
				.usingJobData("jobName",jobName)
				.build();
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
		CronTrigger cronTrigger = TriggerBuilder
				.newTrigger()
				.withIdentity(trigger, group)
				.withSchedule(scheduleBuilder)
				.build();
		
		if(exists){
			schedulerFactoryBean.getScheduler().rescheduleJob(new TriggerKey(trigger,group), cronTrigger);
			schedulerFactoryBean.getScheduler().resumeJob(new JobKey(jobName, group));
		}else {
			schedulerFactoryBean.getScheduler().scheduleJob(jobDetail,cronTrigger);
		}
	}


	@Override
	public void disactive(PlJobDTO jobDto) throws Exception {

		PlJob jobPO = baseMapper.selectById(jobDto.getId());
		Assert.notNull(jobPO,"调度任务不存在!");
		
		//更新qrtz_job状态
		String jobName = jobPO.getJobName();
		String group = jobPO.getJobGroup();
		JobKey jobkey = new JobKey(jobName, group);
		boolean exists = schedulerFactoryBean.getScheduler().checkExists(jobkey);
		if(exists) {
			schedulerFactoryBean.getScheduler().pauseJob(jobkey);
		}
		
		//更新调度任务状态
		updJobStatus(jobPO,"否");
	}

	@Override
	public void updJobCron(PlJobDTO dto) throws Exception {
		QueryWrapper<PlJob> where = new QueryWrapper<PlJob>();
		where.eq("id", dto.getId());
		PlJob pljob = baseMapper.selectOne(where);
		
		//更新pljob表信息
		updPlJobCron(pljob,dto.getJobCron());
		
		//重新设置qrtz job触发器
		reschedulerJob(pljob,dto.getJobCron());
	}
	
	//更新pljob表信息
	private void updPlJobCron(PlJob pljob,String cron) {
		UpdateWrapper<PlJob> where = new UpdateWrapper<PlJob>();
		where.eq("id", pljob.getId());
		pljob.setJobCron(cron);
		baseMapper.update(pljob, where);
	}
	
	//重新设置qrtz job触发器
	private void reschedulerJob(PlJob job,String cron) throws Exception {
        String triggerName = job.getJobName()+"Trigger";
        String triggerGroup = job.getJobGroup();
        String cronExpression = job.getJobCron();
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule(cronExpression);
        CronTrigger trigger = (CronTrigger) schedulerFactoryBean.getScheduler().getTrigger(triggerKey);
        // 按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder()
                .withIdentity(triggerName, triggerGroup)
                .withSchedule(builder)
                .build();
        // 按新的trigger重新设置job执行
        schedulerFactoryBean.getScheduler().rescheduleJob(triggerKey, trigger);
	}
	
	
	@Override
	public void delJob(PlJobDTO jobDto) throws Exception {
		PlJob jobPO = baseMapper.selectById(jobDto.getId());
		
		Assert.notNull(jobPO,"调度任务不存在!");
		
		deleteQrtz(jobPO);
		
		deletePlJob(jobDto);
	}

	private void deletePlJob(PlJobDTO job) {
		baseMapper.deleteById(job.getId());
	}
	
    private void deleteQrtz(PlJob job) throws Exception {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        schedulerFactoryBean.getScheduler().pauseTrigger(TriggerKey.triggerKey(jobName,jobGroup));
        schedulerFactoryBean.getScheduler().unscheduleJob(TriggerKey.triggerKey(jobName,jobGroup));
        schedulerFactoryBean.getScheduler().deleteJob(JobKey.jobKey(jobName, jobGroup));
    }
    
    
    @Override
    public void execute(PlJobDTO dto) throws Exception {
		PlJob jobPO = baseMapper.selectById(dto.getId());
        String jobName = jobPO.getJobName();
        String jobGroup = jobPO.getJobGroup();
        schedulerFactoryBean.getScheduler().triggerJob(JobKey.jobKey(jobName, jobGroup));
    }

	@Override
	public void updJobBase(PlJobDTO jobDto) throws Exception {
		UpdateWrapper<PlJob> where = new UpdateWrapper<PlJob>();
		where.eq("id", jobDto.getId());
		
		
		PlJob updColumn = new PlJob();
		updColumn.setDescription(jobDto.getDescription());
		updColumn.setEnvironmentId(jobDto.getEnvironmentId());
		updColumn.setRequestDateType(jobDto.getRequestDateType());
		updColumn.setQuerySql(jobDto.getQuerySql());
		updColumn.setStatusField(jobDto.getStatusField());
		updColumn.setSuccessStatusValue(jobDto.getSuccessStatusValue());
		updColumn.setTargetApiId(jobDto.getTargetApiId());
		updColumn.setUpdateSql(jobDto.getUpdateSql());
		updColumn.setUpdColumn(jobDto.getUpdColumn());
		
		baseMapper.update(updColumn, where);
	}
}
